﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WinRTFramework.FrameworkConfiguration;
using WinRTFramework.FrameworkCore;
using WinRTFramework.FrameworkCore.Managers;
using WinRTFramework.FrameworkCore.Services;
using WinRTFramework.Interfaces.AppStates;
using WinRTFramework.Interfaces.Contracts.Search;
using WinRTFramework.Interfaces.Contracts.Sharing;
using WinRTFramework.Interfaces.Navigation;
using WinRTFramework.Interfaces.Navigation.ViewModel;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using WinRTFramework.Contracts;

namespace WinRTFramework
{
    public class WinRTContainer : IServiceInjector
    {
        private readonly IApplicationAdapter _applicationAdapter;
        private readonly Frame _rootFrame;
        
        IIoCAdapter _iocAdapter;
        IViewViewModelMapper _viewProvider;
        private readonly WinRTContainerOptions _options;

        SettingsManager _settingsManager;
        SharingSourceManager _sharingSourceManager;
        NavigationManager _navigationManager;
        SearchManager _searchManager;

        public class ExtensionsContainer
        {
            public ISearchActivationViewModelTypeSelector SearchActivationViewModelTypeSelector { get; set; }
        }

        public class WinRTContainerOptions
        {
            public bool IsSearchSupported { get; set; }
        }

        private WinRTContainer(IApplicationAdapter applicationAdapter, Frame rootFrame, IIoCAdapter iocAdapter, IViewViewModelMapper viewProvider, WinRTContainerOptions options)
        {
            _applicationAdapter = applicationAdapter;
            _rootFrame = rootFrame;
            _iocAdapter = iocAdapter;
            _viewProvider = viewProvider;
            _options = options;

            Extensions = new ExtensionsContainer();
        }

        public static WinRTContainer CreateFrom(IApplicationAdapter applicationAdapter, Frame rootFrame, IIoCAdapter iocAdapter, IViewViewModelMapper viewProvider)
        {
            return CreateFrom(applicationAdapter, rootFrame, iocAdapter, viewProvider, new WinRTContainerOptions());
        }

        public static WinRTContainer CreateFrom(IApplicationAdapter applicationAdapter, Frame rootFrame, IIoCAdapter iocAdapter, IViewViewModelMapper viewProvider, WinRTContainerOptions options)
        {
            var container = new WinRTContainer(applicationAdapter, rootFrame, iocAdapter, viewProvider, options);
            container.Initialize();
            return container;
        }
        
        private void Initialize()
        {
            NavigationService = new NavigationService(_rootFrame, _viewProvider);
            SharingService = new SharingService();
            
            _settingsManager = SettingsManager.CreateFrom(_iocAdapter, _viewProvider);
            _sharingSourceManager = new SharingSourceManager();
            _navigationManager = NavigationManager.CreateFrom(_applicationAdapter, _rootFrame, _viewProvider, this, new NavigationManager.NavigationManagerOptions() { HandleResumeAndSuspend = true });
            
            if(_options.IsSearchSupported)
                _searchManager = new SearchManager(_rootFrame, _iocAdapter, NavigationService);

            RegisterTransientStateTypes();
        }

        private void RegisterTransientStateTypes()
        {
            List<Type> transientTypes = new List<Type>();
            foreach(var registeredType in _iocAdapter.GetAllRegisteredTypes())
            {
                var instance = _iocAdapter.GetInstanceOfType(registeredType);
                if(instance is ISupportTransientState)
                {
                    transientTypes.AddRange(((ISupportTransientState)instance).GetTransientStateTypes());
                }
            }
            SuspensionManager.KnownTypes.AddRange(transientTypes.Distinct());
        }
        
        public INavigationService NavigationService { get; private set; }
        public ISharingService SharingService { get; private set; }
        public ExtensionsContainer Extensions { get; private set; }

        #region IServiceInjector
        public void InjectServicesIntoViewModel(object viewModel)
        {
            if(viewModel is IRequireNavigationService)
            {
                ((IRequireNavigationService) viewModel).NavigationService = NavigationService;
            }

            if(viewModel is IRequireSharingService)
            {
                ((IRequireSharingService) viewModel).SharingService = SharingService;
            }
        }
        #endregion

        public void HandleSearchActivation(string language, string queryText)
        {
            if(!_options.IsSearchSupported)
                throw new InvalidOperationException("Search Activation can only be handled if Search is supported. Change options of WinRTContainer instance.");

            _searchManager.SearchActivationViewModelTypeSelector = Extensions.SearchActivationViewModelTypeSelector;
            _searchManager.HandleSearchActivation(language, queryText);
        }
    }
}
